<!doctype HTML public "-//W3C//DTD HTML 4.0 Frameset//EN">
<html>
<title>Bloomberg Development Environment</title>
<html>
<pre>
// Copyright 2022-2023 Bloomberg Finance L.P.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// bmqt_subscription.h                                                -*-C++-*-
#ifndef INCLUDED_BMQT_SUBSCRIPTION
#define INCLUDED_BMQT_SUBSCRIPTION

//@PURPOSE: Provide a value-semantic types for subscription related API.
//
//@CLASSES:
//  bmqt::Subscription_Handle:      uniquely identifies Subscription
//  bmqt::Subscription_Expression:  Subscription criteria
//  bmqt::Subscription:             Subscription parameters
//
//@DESCRIPTION: &#39;bmqt::Subscription&#39; provides a value-semantic type carried
// by &#39;bmqt::QueueOptions&#39;, when opening and configuring a queue.
//
//@NOTE: Experimental.  Do not use until this feature is announced.
//


// BMQ
#include &lt;bmqscm_version.h&gt;
#include &lt;bmqt_correlationid.h&gt;

//BDE
#include &lt;bsl_optional.h&gt;
#include &lt;bsl_ostream.h&gt;
#include &lt;bsl_string.h&gt;
#include &lt;bslim_printer.h&gt;
#include &lt;bslma_allocator.h&gt;
#include &lt;bsls_types.h&gt;


namespace BloombergLP {

namespace bmqt {

class QueueOptions;
                            // =========================
                            // class Subscription_Handle
                            // =========================

class SubscriptionHandle {
    // Value-semantic type for unique Subscription id.
  private:
    // PRIVATE DATA
    unsigned int                d_id;
                                    // Internal, unique key

    const bmqt::CorrelationId   d_correlationId;
                                    // User-specified, not required to be
                                    // unique
  private:
    // PRIVATE CLASS METHODS
    static unsigned int nextId();

  public:
    // CREATORS
    SubscriptionHandle(const bmqt::CorrelationId&amp; cid);
    SubscriptionHandle(const SubscriptionHandle&amp; other);

    // ACCESSORS
    const bmqt::CorrelationId&amp; correlationId() const;

    unsigned int id() const;

    bsl::ostream&amp; print(bsl::ostream&amp; stream,
                        int           level          = 0,
                        int           spacesPerLevel = 4) const;
        // Format this object to the specified output &#39;stream&#39; at the (absolute
        // value of) the optionally specified indentation &#39;level&#39; and return a
        // reference to &#39;stream&#39;.  If &#39;level&#39; is specified, optionally specify
        // &#39;spacesPerLevel&#39;, the number of spaces per indentation level for
        // this and all of its nested objects.  If &#39;level&#39; is negative,
        // suppress indentation of the first line.  If &#39;spacesPerLevel&#39; is
        // negative format the entire output on one line, suppressing all but
        // the initial indentation (as governed by &#39;level&#39;).  If &#39;stream&#39; is
        // not valid on entry, this operation has no effect.

    // FRIENDS
    friend bool operator&lt;(const SubscriptionHandle&amp; lhs,
                          const SubscriptionHandle&amp; rhs);
    friend bool operator==(const SubscriptionHandle&amp; lhs,
                           const SubscriptionHandle&amp; rhs);
    friend bool operator!=(const SubscriptionHandle&amp; lhs,
                           const SubscriptionHandle&amp; rhs);

    template &lt;class HASH_ALGORITHM&gt;
    friend void hashAppend(HASH_ALGORITHM&amp;            hashAlgo,
                           const SubscriptionHandle&amp; id);

        // Will only consider &#39;d_id&#39; field when comparing &#39;lhs&#39; and &#39;rhs&#39;
};

class SubscriptionExpression {
    // Value-semantic type to carry Subscription criteria.

 public:
    // TYPES
    enum Enum {
        // Enum representing criteria format
          e_NONE        = 0     // EMPTY
        , e_VERSION_1   = 1     // Simple Evaluator
    };

 private:
    bsl::string     d_expression;   // e.g., &quot;firmId == foo&quot;

    Enum            d_version;      // Required to support newer style
                                    // of expressions in future

  public:
    // CREATORS
    SubscriptionExpression();
    SubscriptionExpression(const bsl::string&amp;  expression, Enum version);

    // ACCESSORS
    const bsl::string&amp; text() const;

    Enum version() const;

    bool isValid() const;

    bsl::ostream&amp; print(bsl::ostream&amp; stream,
                        int           level          = 0,
                        int           spacesPerLevel = 4) const;
        // Format this object to the specified output &#39;stream&#39; at the (absolute
        // value of) the optionally specified indentation &#39;level&#39; and return a
        // reference to &#39;stream&#39;.  If &#39;level&#39; is specified, optionally specify
        // &#39;spacesPerLevel&#39;, the number of spaces per indentation level for
        // this and all of its nested objects.  If &#39;level&#39; is negative,
        // suppress indentation of the first line.  If &#39;spacesPerLevel&#39; is
        // negative format the entire output on one line, suppressing all but
        // the initial indentation (as governed by &#39;level&#39;).  If &#39;stream&#39; is
        // not valid on entry, this operation has no effect.
};

class Subscription {
    // Value-semantic type to carry Subscription parameters.

  public:
    // PUBLIC CONSTANTS
    static const int k_CONSUMER_PRIORITY_MIN;
                                        // Constant representing the minimum
                                        // valid consumer priority

    static const int k_CONSUMER_PRIORITY_MAX;
                                        // Constant representing the maximum
                                        // valid consumer priority

    static const int  k_DEFAULT_MAX_UNCONFIRMED_MESSAGES;
    static const int  k_DEFAULT_MAX_UNCONFIRMED_BYTES;
    static const int  k_DEFAULT_CONSUMER_PRIORITY;

  private:
    // PRIVATE DATA
    bsl::optional&lt;int&gt;      d_maxUnconfirmedMessages;
                                        // Maximum number of outstanding
                                        // messages that can be sent by the
                                        // broker without being confirmed.

    bsl::optional&lt;int&gt;      d_maxUnconfirmedBytes;
                                        // Maximum accumulated bytes of all
                                        // outstanding messages that can be
                                        // sent by the broker without being
                                        // confirmed.

    bsl::optional&lt;int&gt;      d_consumerPriority;
                                        // Priority of a consumer with respect
                                        // to delivery of messages

    SubscriptionExpression  d_expression;

  public:
    // CREATORS
    Subscription();

        // Create a new Subscription
    Subscription(const Subscription&amp;  other);
        // Create a new Subscription by copying values from the specified
        // &#39;other&#39;.

    // MANIPULATORS
    Subscription&amp; setMaxUnconfirmedMessages(int value);
        // Set the maxUnconfirmedMessages to the specified &#39;value&#39;.  The
        // behavior is undefined unless &#39;value &gt;= 0&#39;. If the specified &#39;value&#39;
        // is set to 0, it means that the consumer does not receive any
        // messages.  This might be useful when the consumer is shutting down
        // and wants to process only pending messages, or when it is unable to
        // process new messages because of transient issues.

    Subscription&amp; setMaxUnconfirmedBytes(int value);
        // Set the maxUnconfirmedBytes to the specified &#39;value&#39;.  The behavior
        // is undefined unless &#39;value &gt;= 0&#39;.

    Subscription&amp; setConsumerPriority(int value);
        // Set the consumerPriority to the specified &#39;value&#39;.  The behavior is
        // undefined unless &#39;k_CONSUMER_PRIORITY_MIN &lt;= value &lt;=
        // k_CONSUMER_PRIORITY_MAX&#39;

    Subscription&amp; setExpression(const SubscriptionExpression&amp; value);

    // ACCESSORS
    int maxUnconfirmedMessages() const;
        // Get the number for the maxUnconfirmedMessages parameter.

    int maxUnconfirmedBytes() const;
        // Get the number for the maxUnconfirmedBytes parameter.

    int consumerPriority() const;
        // Get the number for the consumerPriority parameter.

    const SubscriptionExpression&amp; expression() const;

    bool hasMaxUnconfirmedMessages() const;
        // Returns whether &#39;maxUnconfirmedMessages&#39; has been set for this
        // object, or whether it implicitly holds
        // &#39;k_DEFAULT_MAX_UNCONFIRMED_MESSAGES&#39;.

    bool hasMaxUnconfirmedBytes() const;
        // Returns whether &#39;maxUnconfirmedBytes&#39; has been set for this object,
        // or whether it implicitly holds &#39;k_DEFAULT_MAX_UNCONFIRMED_BYTES&#39;.

    bool hasConsumerPriority() const;
        // Returns whether &#39;consumerPriority&#39; has been set for this object, or
        // whether it implicitly holds &#39;k_DEFAULT_CONSUMER_PRIORITY&#39;.

    bsl::ostream&amp; print(bsl::ostream&amp; stream,
                        int           level          = 0,
                        int           spacesPerLevel = 4) const;
        // Format this object to the specified output &#39;stream&#39; at the (absolute
        // value of) the optionally specified indentation &#39;level&#39; and return a
        // reference to &#39;stream&#39;.  If &#39;level&#39; is specified, optionally specify
        // &#39;spacesPerLevel&#39;, the number of spaces per indentation level for
        // this and all of its nested objects.  If &#39;level&#39; is negative,
        // suppress indentation of the first line.  If &#39;spacesPerLevel&#39; is
        // negative format the entire output on one line, suppressing all but
        // the initial indentation (as governed by &#39;level&#39;).  If &#39;stream&#39; is
        // not valid on entry, this operation has no effect.
};

// FREE OPERATORS
bsl::ostream&amp; operator&lt;&lt;(bsl::ostream&amp; stream, const Subscription&amp; rhs);
    // Format the specified &#39;rhs&#39; to the specified output &#39;stream&#39; and return a
    // reference to the modifiable &#39;stream&#39;.


// ============================================================================
//                             INLINE DEFINITIONS
// ============================================================================

                             // ----------------------
                             // class Subscription_Handle
                             // ----------------------

inline
SubscriptionHandle::SubscriptionHandle(const bmqt::CorrelationId&amp; cid)
: d_id(nextId())
, d_correlationId(cid)
{
    // NOTHING
}

inline
SubscriptionHandle::SubscriptionHandle(const SubscriptionHandle&amp; other)
: d_id(other.d_id)
, d_correlationId(other.d_correlationId)
{
    // NOTHING
}

// ACCESSORS
inline
const bmqt::CorrelationId&amp;
SubscriptionHandle::correlationId() const
{
    return d_correlationId;
}

inline
unsigned int
SubscriptionHandle::id() const
{
    return d_id;
}

inline
bsl::ostream&amp;
SubscriptionHandle::print(bsl::ostream&amp; stream,
                          int           level,
                          int           spacesPerLevel) const
{
    if (stream.bad()) {
        return stream;                                                // RETURN
    }

    bslim::Printer printer(&amp;stream, level, spacesPerLevel);
    printer.start();

    printer.printAttribute(&quot;id&quot;, d_id);
    printer.printAttribute(&quot;CorrelationId&quot;, d_correlationId);

    printer.end();

    return stream;
}
                             // ----------------------------
                             // class SubscriptionExpression
                             // ----------------------------
inline
SubscriptionExpression::SubscriptionExpression()
: d_expression()
, d_version(e_NONE)
{
    // NOTHING
}

inline
SubscriptionExpression::SubscriptionExpression(const bsl::string&amp;  expression,
                                               Enum                version)
: d_expression(expression)
, d_version(version)
{
    // NOTHING
}

inline
const bsl::string&amp;
SubscriptionExpression::text() const
{
    return d_expression;
}

inline
SubscriptionExpression::Enum
SubscriptionExpression::version() const
{
    return d_version;
}

inline
bool
SubscriptionExpression::isValid() const
{
    return
        d_expression.length() == 0 ? d_version == e_NONE : d_version &gt; e_NONE;
}

inline
bsl::ostream&amp;
SubscriptionExpression::print(bsl::ostream&amp; stream,
                              int           level,
                              int           spacesPerLevel) const
{
    if (stream.bad()) {
        return stream;                                                // RETURN
    }

    bslim::Printer printer(&amp;stream, level, spacesPerLevel);
    printer.start();

    printer.printAttribute(&quot;Expression&quot;, d_expression);
    printer.printAttribute(&quot;Version&quot;, d_version);

    printer.end();

    return stream;
}

                             // ----------------------
                             // class Subscription
                             // ----------------------

inline
Subscription::Subscription()
: d_maxUnconfirmedMessages()
, d_maxUnconfirmedBytes()
, d_consumerPriority()
, d_expression()
{
    // NOTHING
}

inline
Subscription::Subscription(const Subscription&amp; other)
: d_maxUnconfirmedMessages(other.d_maxUnconfirmedMessages)
, d_maxUnconfirmedBytes(other.d_maxUnconfirmedBytes)
, d_consumerPriority(other.d_consumerPriority)
, d_expression(other.d_expression)
{
    // NOTHING
}

inline
bsl::ostream&amp;
Subscription::print(bsl::ostream&amp; stream,
                        int           level,
                        int           spacesPerLevel) const
{
    if (stream.bad()) {
        return stream;                                                // RETURN
    }

    bslim::Printer printer(&amp;stream, level, spacesPerLevel);
    printer.start();
    printer.printAttribute(&quot;maxUnconfirmedMessages&quot;, maxUnconfirmedMessages());
    printer.printAttribute(&quot;maxUnconfirmedBytes&quot;,    maxUnconfirmedBytes());
    printer.printAttribute(&quot;consumerPriority&quot;,       consumerPriority());

    d_expression.print(stream, level, spacesPerLevel);

    printer.end();

    return stream;
}

// MANIPULATORS
inline
Subscription&amp;
Subscription::setMaxUnconfirmedMessages(int value)
{
    d_maxUnconfirmedMessages.emplace(value);
    return *this;
}

inline
Subscription&amp;
Subscription::setMaxUnconfirmedBytes(int value)
{
    d_maxUnconfirmedBytes.emplace(value);
    return *this;
}

inline
Subscription&amp;
Subscription::setConsumerPriority(int value)
{
    d_consumerPriority.emplace(value);
    return *this;
}

inline
Subscription&amp;
Subscription::setExpression(const SubscriptionExpression&amp; value)
{
    d_expression = value;
    return *this;
}

// ACCESSORS
inline
int
Subscription::maxUnconfirmedMessages() const
{
    return d_maxUnconfirmedMessages.value_or(
                                           k_DEFAULT_MAX_UNCONFIRMED_MESSAGES);
}

inline
int
Subscription::maxUnconfirmedBytes() const
{
    return d_maxUnconfirmedBytes.value_or(k_DEFAULT_MAX_UNCONFIRMED_BYTES);
}

inline
int
Subscription::consumerPriority() const
{
    return d_consumerPriority.value_or(k_DEFAULT_CONSUMER_PRIORITY);
}

inline
const SubscriptionExpression&amp;
Subscription::expression() const
{
    return d_expression;
}

inline
bool
Subscription::hasMaxUnconfirmedMessages() const
{
    return d_maxUnconfirmedMessages.has_value();
}

inline
bool
Subscription::hasMaxUnconfirmedBytes() const
{
    return d_maxUnconfirmedBytes.has_value();
}

inline
bool
Subscription::hasConsumerPriority() const
{
    return d_consumerPriority.has_value();
}

// FREE FUNCTIONS
template &lt;class HASH_ALGORITHM&gt;
void
hashAppend(HASH_ALGORITHM&amp; hashAlgo, const SubscriptionHandle&amp; id)
    // Apply the specified &#39;hashAlgo&#39; to the specified &#39;id&#39;.
{
    using bslh::hashAppend; // for ADL
    hashAppend(hashAlgo, id.d_id);
}

inline
bool
operator&lt;(const SubscriptionHandle&amp; lhs, const SubscriptionHandle&amp; rhs)
{
    return lhs.d_id &lt; rhs.d_id;
}

inline
bool
operator==(const SubscriptionHandle&amp; lhs, const SubscriptionHandle&amp; rhs)
{
    return lhs.d_id == rhs.d_id;
}

inline
bool
operator!=(const SubscriptionHandle&amp; lhs, const SubscriptionHandle&amp; rhs)
{
    return lhs.d_id != rhs.d_id;
}

inline
bsl::ostream&amp;
operator&lt;&lt;(bsl::ostream&amp;stream, const Subscription&amp; rhs)
{
    return rhs.print(stream, 0, -1);
}


}  // close package namespace

}  // close enterprise namespace

#endif
</pre>
</body>
</html>
